home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / domain.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  53KB  |  2,335 lines

  1. /*
  2.  *      DOMAIN.C -- domain name system stub resolver
  3.  *
  4.  *      Original code by Phil Karn, KA9Q
  5.  *
  6.  *      04-90 -- Bill Simpson added address->name resolution, time-to-live,
  7.  *      thru     memory caching, generalized multi-record multi-type searches,
  8.  *      10-90    and many minor changes to conform more closely to the RFCs.
  9.  *
  10.  *  06-89 -- Gerard van der Grinten, PA0GRI
  11.  *      thru     Lots of changes and inprovements including server code.
  12.  *      02-91
  13.  *
  14.  *  Jan 92  Bill Simpson added CNAME support to domainsuffix routine.
  15.  *
  16.  *  Jun 92  Johan. K. Reinalda, WG7J
  17.  *          Ported the Domain Name Server from PA0GRI's 910828 .
  18.  *          Version info see down below
  19.  *
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include <time.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include "global.h"
  28. #include "config.h"
  29. #include "mbuf.h"
  30. #include "netuser.h"
  31. #include "ip.h"
  32. #include "socket.h"
  33. #include "cmdparse.h"
  34. #include "proc.h"
  35. #include "domain.h"
  36. #include "commands.h"
  37. #include "files.h"
  38. #include "getline.h" 
  39.  
  40. #ifdef UNIX
  41. #define fprintf tfprintf
  42. #define printf tprintf
  43. #ifdef __cplusplus
  44. extern "C" {
  45. #endif
  46. extern int unlink __ARGS((const char *));
  47. #ifdef __cplusplus
  48. }
  49. #endif
  50. #endif
  51.  
  52. #undef  DEBUG               /* for certain trace messages */
  53. #undef  DEBUG_PAIN                      /* for painful debugging */
  54.  
  55. extern int main_exit;                   /* from main program (flag) */
  56. extern int Mprunning;                   /* from main program (flag) */
  57. int DTranslate;                 /* do IP address to domain name translation */
  58. int DVerbose;                   /* Use all of resolved name or first element */
  59.  
  60.  
  61. static struct rr *Dcache;       /* Cache of resource records */
  62. static int Dcache_size = 20;            /* size limit */
  63. static time_t Dcache_time = 0L;         /* timestamp */
  64.  
  65. static int Dfile_clean;             /* discard expired records (flag) */
  66. static int Dfile_reading;           /* read interlock (count) */
  67. static int Dfile_writing;           /* write interlock (count) */
  68.  
  69. struct proc *Dfile_updater;
  70. static int32 Dfile_wait_absolute;       /* timeout Clock time */
  71. static int Dfile_wait_relative = 300;   /* timeout file activity (seconds) */
  72.  
  73. static struct dserver *Dservers;        /* List of potential servers */
  74. static int Dserver_retries = 2;         /* Attempts to reach servers */
  75. static int32 Dserver_maxwait = 60L;     /* maximum server timeout limit (seconds) */
  76.  
  77. static char *Dsuffix;           /* Default suffix for names without periods */
  78. static int Dsuffixl;            /* size of Dsuffix (less computing to do */
  79. static int Dtrace;
  80. static char *Dtypes[] = {
  81.     "",
  82.     "A",
  83.     "NS",
  84.     "MD",
  85.     "MF",
  86.     "CNAME",
  87.     "SOA",
  88.     "MB",
  89.     "MG",
  90.     "MR",
  91.     "NULL",
  92.     "WKS",
  93.     "PTR",
  94.     "HINFO",
  95.     "MINFO",
  96.     "MX",
  97.     "TXT"
  98. };
  99. #define NDTYPES 17
  100. static char delim[] = " \t\r\n";
  101.  
  102. static int docache __ARGS((int argc,char *argv[],void *p));
  103. static int dosuffix __ARGS((int argc,char *argv[],void *p));
  104. static int dotranslate __ARGS((int argc,char *argv[],void *p));
  105. static int doverbose __ARGS((int argc,char *argv[],void *p));
  106.  
  107. static int docacheclean __ARGS((int argc,char *argv[],void *p));
  108. static int docachelist __ARGS((int argc,char *argv[],void *p));
  109. static int docachesize __ARGS((int argc,char *argv[],void *p));
  110. static int docachewait __ARGS((int argc,char *argv[],void *p));
  111. static int docacheflush __ARGS((int argc,char *argv[],void *p));
  112.  
  113. static void dlist_add __ARGS((struct dserver *dp));
  114. static void dlist_drop __ARGS((struct dserver *dp));
  115. static int dodnsadd __ARGS((int argc,char *argv[],void *p));
  116. static int dodnsdrop __ARGS((int argc,char *argv[],void *p));
  117. static int dodnslist __ARGS((int argc,char *argv[],void *p));
  118. static int dodnsmaxw __ARGS((int argc,char *argv[],void *p));
  119. static int dodnsretry __ARGS((int argc,char *argv[],void *p));
  120. static int dodnstrace __ARGS((int argc,char *argv[],void *p));
  121. static int dodnsserver __ARGS((int argc,char *argv[],void *p));
  122. static int dodomlook __ARGS((int argc,char *argv[],void *p));
  123.  
  124. static int check_ttl __ARGS((struct rr *rrlp));
  125. static int compare_rr __ARGS((struct rr *search_rrp,struct rr *target_rrp));
  126. static int compare_rr_list __ARGS((struct rr *rrlp,struct rr *target_rrp));
  127. static struct rr *copy_rr __ARGS((struct rr *rrp));
  128. static struct rr *copy_rr_list __ARGS((struct rr *rrlp));
  129. static struct rr *make_rr __ARGS((int source,
  130.     char *dname,int16 class,int16 type,int32 ttl,int16 rdl,void *data));
  131.  
  132. static void dcache_add __ARGS((struct rr *rrlp));
  133. static void dcache_drop __ARGS((struct rr *rrp));
  134. static struct rr *dcache_search __ARGS((struct rr *rrlp));
  135. static void dcache_update __ARGS((struct rr *rrlp));
  136.  
  137. static struct rr *get_rr __ARGS((FILE *fp, struct rr *lastrrp));
  138. static void put_rr __ARGS((FILE *fp,struct rr *rrp));
  139. static struct rr *dfile_search __ARGS((struct rr *rrlp));
  140. static void dfile_update __ARGS((int s,void *unused,void *p));
  141.  
  142. static void dumpdomain __ARGS((struct dhdr *dhp,int32 rtt));
  143. static int dns_makequery __ARGS((int16 op,struct rr *rrp,
  144.     char *buffer,int16 buflen));
  145. static void dns_query __ARGS((struct rr *rrlp));
  146.  
  147. static int isaddr __ARGS((char *s));
  148. static struct rr *resolver __ARGS((struct rr *rrlp));
  149.  
  150. static void free_dhdr __ARGS((struct dhdr *));
  151. static void proc_query __ARGS((int,void *,void *));
  152. static void drx __ARGS((int,void *,void *));
  153.  
  154. /**
  155.  **     Domain Resolver Commands
  156.  **/
  157.  
  158. static struct cmds Dcmds[] = {
  159.     "addserver",    dodnsadd,       0, 2, "add <hostid>",
  160.     "cache",        docache,        0, 0, NULLCHAR,
  161. #ifdef DSERVER
  162.     "dns",      dodnsserver,0, 0, NULLCHAR,
  163. #endif
  164.     "dropserver",   dodnsdrop,      0, 2, "drop <hostid>",
  165.     "list",         dodnslist,      0, 0, NULLCHAR,
  166. #ifdef ALLCMD
  167.     "look",     dodomlook,  512, 2, "look <search text>",
  168. #endif
  169.     "maxwait",  dodnsmaxw,  0, 0, NULLCHAR,
  170.     "retry",        dodnsretry,     0, 0, NULLCHAR,
  171.     "suffix",       dosuffix,       0, 0, NULLCHAR,
  172.     "trace",    dodnstrace, 0, 0, NULLCHAR,
  173.     "translate",    dotranslate,    0, 0, NULLCHAR,
  174.     "verbose",      doverbose,      0, 0, NULLCHAR,
  175.     NULLCHAR,
  176. };
  177.  
  178. static struct cmds Dcachecmds[] = {
  179.     "clean",        docacheclean,   0, 0, NULLCHAR,
  180.     "list",         docachelist,    0, 0, NULLCHAR,
  181.     "size",         docachesize,    0, 0, NULLCHAR,
  182.     "wait",         docachewait,    0, 0, NULLCHAR,
  183.     "flush",    docacheflush,    0, 0, NULLCHAR,
  184.     NULLCHAR,
  185. };
  186.  
  187. int
  188. dodomain(argc,argv,p)
  189. int argc;
  190. char *argv[];
  191. void *p;
  192. {
  193.     return subcmd(Dcmds,argc,argv,p);
  194. }
  195.  
  196. int
  197. docache(argc,argv,p)
  198. int argc;
  199. char *argv[];
  200. void *p;
  201. {
  202.     return subcmd(Dcachecmds,argc,argv,p);
  203. }
  204.  
  205. static int
  206. dosuffix(argc,argv,p)
  207. int argc;
  208. char *argv[];
  209. void *p;
  210. {
  211.     if(argc < 2){
  212.         if(Dsuffix != NULLCHAR)
  213.             tprintf("%s\n",Dsuffix);
  214.         else
  215.             tprintf("No domain suffix defined.\n");
  216.         return 0;
  217.     }
  218.     if(strcmp(argv[1],"none") == 0){
  219.         if(Dsuffix != NULLCHAR){
  220.             free(Dsuffix);
  221.             Dsuffix = NULLCHAR ;    /* clear out suffix */
  222.             Dsuffixl = 0;
  223.         }
  224.     } else 
  225.         if(argv[1][strlen(argv[1])-1] != '.'){
  226.             tprintf(" %s is not a valid suffix.\n",argv[1]);
  227.             return 1;
  228.         } else {
  229.             free(Dsuffix);
  230.             Dsuffix = strdup(argv[1]);
  231.             Dsuffixl = strlen(Dsuffix);
  232.         }
  233.     return 0;
  234. }
  235.  
  236. static int
  237. dotranslate(argc,argv,p)
  238. int argc;
  239. char *argv[];
  240. void *p;
  241. {
  242.     return setbool( &DTranslate, "Translate IP address to host names", argc,argv );
  243. }
  244.  
  245. static int
  246. doverbose(argc,argv,p)
  247. int argc;
  248. char *argv[];
  249. void *p;
  250. {
  251.     return setbool( &DVerbose, "Verbose translation of host names", argc,argv );
  252. }
  253.  
  254. static int
  255. dodnsmaxw(argc,argv,p)
  256. int argc;
  257. char *argv[];
  258. void *p;
  259. {
  260.     return setlong(&Dserver_maxwait,"Server response timeout limit (sec)",argc,argv);
  261. }
  262.  
  263. static int
  264. docacheclean(argc,argv,p)
  265. int argc;
  266. char *argv[];
  267. void *p;
  268. {
  269.     return setbool( &Dfile_clean, "discard expired records", argc,argv );
  270. }
  271.  
  272. static int
  273. docachelist(argc,argv,p)
  274. int argc;
  275. char *argv[];
  276. void *p;
  277. {
  278.     struct rr *rrp;
  279.  
  280.     (void)dcache_search(NULLRR); /* update ttl */
  281. #ifndef UNIX
  282.     rflush();
  283. #endif
  284.     for(rrp=Dcache;rrp!=NULLRR;rrp=rrp->next)
  285.     {
  286.         put_rr(stdout,rrp);
  287.     }
  288.     return 0;
  289. }
  290.  
  291. static int
  292. docachesize(argc,argv,p)
  293. int argc;
  294. char *argv[];
  295. void *p;
  296. {
  297.     int newsize;
  298.     int oldsize;
  299.     int result;
  300.  
  301.     newsize = oldsize = Dcache_size;
  302.     result = setint( &newsize, "memory cache size", argc,argv );
  303.  
  304.     if(newsize > 0){
  305.         Dcache_size = newsize;
  306.         if(newsize < oldsize){
  307.             (void)dcache_search(NULLRR); /* update size */
  308.         }
  309.     }
  310.     return result;
  311. }
  312.  
  313. static int
  314. docachewait(argc,argv,p)
  315. int argc;
  316. char *argv[];
  317. void *p;
  318. {
  319.     return setint( &Dfile_wait_relative, "time before file update (seconds)", argc,argv );
  320. }
  321.  
  322. /*
  323.  * 931014 KF8NH: empty the cache completely.  Useful for hot updates to
  324.  * domain.txt, which tend to be necessary around here (we're in the process
  325.  * of subnetting, one bloody node at a time...)
  326.  */
  327.  
  328. static int
  329. docacheflush(argc,argv,p)
  330. int argc;
  331. char *argv[];
  332. void *p;
  333. {
  334.     free_rr(Dcache);
  335.     Dcache = NULLRR;
  336.     return 0;
  337. }
  338.  
  339. static void
  340. dlist_add(dp)
  341. register struct dserver *dp;
  342. {
  343.     dp->prev = NULLDOM;
  344.     dp->next = Dservers;
  345.     if(Dservers != NULLDOM)
  346.         Dservers->prev = dp;
  347.     Dservers = dp;
  348. }
  349.  
  350. static void
  351. dlist_drop(dp)
  352. register struct dserver *dp;
  353. {
  354.     if(dp->prev != NULLDOM)
  355.         dp->prev->next = dp->next;
  356.     else
  357.         Dservers = dp->next;
  358.     if(dp->next != NULLDOM)
  359.         dp->next->prev = dp->prev;
  360. }
  361.  
  362. static int
  363. dodnsadd(argc,argv,p)
  364. int argc;
  365. char *argv[];
  366. void *p;
  367. {
  368.     int32 address;
  369.  
  370.     if((address = resolve(argv[1])) == 0L){
  371.         tprintf("Resolver %s unknown\n",argv[1]);
  372.         return 1;
  373.     }
  374.     return add_nameserver(address);
  375. }
  376. int
  377. add_nameserver(address)
  378. int32 address;
  379. {
  380.     struct dserver *dp;
  381.  
  382.     dp = (struct dserver *)callocw(1,sizeof(struct dserver));
  383.     dp->address = address;
  384.     dp->srtt = 5000L;               /* About 5 sec */
  385.     dp->mdev = 0;
  386.     dp->timeout = 4 * dp->mdev + dp->srtt;
  387.     dlist_add(dp);
  388.     return 0;
  389. }
  390.  
  391. static int
  392. dodnsdrop(argc,argv,p)
  393. int argc;
  394. char *argv[];
  395. void *p;
  396. {
  397.     struct dserver *dp;
  398.     int32 addr;
  399.  
  400.     addr = resolve(argv[1]);
  401.     for(dp = Dservers;dp != NULLDOM;dp = dp->next)
  402.         if(addr == dp->address)
  403.             break;
  404.  
  405.     if(dp == NULLDOM){
  406.         tprintf("Not found\n");
  407.         return 1;
  408.     }
  409.  
  410.     dlist_drop(dp);
  411.     free((char *)dp);
  412.     return 0;
  413. }
  414.  
  415. static int
  416. dodnslist(argc,argv,p)
  417. int argc;
  418. char *argv[];
  419. void *p;
  420. {
  421.     register struct dserver *dp;
  422.  
  423.     tprintf("Server address          srtt    mdev    timeout  queries responses timeouts\n");
  424.     for(dp = Dservers;dp != NULLDOM;dp = dp->next){
  425.         tprintf("%-20s%8lu%8lu%10lu%10lu%10lu%10lu\n",
  426.          inet_ntoa(dp->address),
  427.          dp->srtt,dp->mdev,dp->timeout,
  428.          dp->queries,dp->responses,dp->timeouts);
  429.     }
  430.     return 0;
  431. }
  432.  
  433. static int
  434. dodnsretry(argc,argv,p)
  435. int argc;
  436. char *argv[];
  437. void *p;
  438. {
  439.     return setint( &Dserver_retries, "server retries", argc,argv );
  440. }
  441.  
  442. static int
  443. dodnstrace(argc,argv,p)
  444. int argc;
  445. char *argv[];
  446. void *p;
  447. {
  448.     return setbool(&Dtrace,"server trace",argc,argv);
  449. }
  450.  
  451.  
  452. /**
  453.  **     Domain Resource Record Utilities
  454.  **/
  455.  
  456. /* check list of resource records for any expired ones.
  457.  * returns number of expired records.
  458.  */
  459. static int
  460. check_ttl(rrlp)
  461. register struct rr *rrlp;
  462. {
  463.     int count = 0;
  464.  
  465.     while(rrlp != NULLRR){
  466.         if(rrlp->ttl == 0L)
  467.             count++;
  468.         rrlp = rrlp->next;
  469.     }
  470.     return count;
  471. }
  472.  
  473. /* Compare two resource records.
  474.  * returns 0 if match, nonzero otherwise.
  475.  */
  476. static int
  477. compare_rr(search_rrp,target_rrp)
  478. register struct rr *search_rrp,*target_rrp;
  479. {
  480.     int i, j, k;
  481.  
  482.     if(search_rrp == NULLRR || target_rrp == NULLRR)
  483.         return -32765;
  484.  
  485.     if(search_rrp->class != target_rrp->class)
  486.         return -32763;
  487.  
  488.     if(search_rrp->type != target_rrp->type
  489.     && (search_rrp->source != RR_QUERY
  490.      || (target_rrp->type != TYPE_CNAME
  491.       && target_rrp->type != TYPE_PTR)))
  492.         return -32761;
  493.  
  494.     if(search_rrp->source != RR_INQUERY){
  495.         i = strlen(search_rrp->name);
  496.         j = strlen(target_rrp->name);
  497.         if(i == j){
  498.             if((k = strnicmp(search_rrp->name,target_rrp->name,(size_t)i)) != 0){
  499.                 return k;
  500.             }
  501.         } else {
  502.  
  503.             if(Dsuffix != NULLCHAR){
  504.                 if(i != j+Dsuffixl+1){
  505.                     return -32759;
  506.                 } else {
  507.                     if(search_rrp->name[j] != '.')
  508.                         return -32755;
  509.                     if(strnicmp(target_rrp->name
  510.                         ,search_rrp->name,(size_t)j) != 0)
  511.                         return -32757;
  512.                 }
  513.             } else {
  514.                 return -32759;
  515.             }
  516.  
  517.         /* match negative records so that they are replaced */
  518.             if(target_rrp->rdlength == 0)
  519.                 return 0;
  520.         }
  521.     }
  522.  
  523.     /* if a query has gotten this far, match it */
  524.     if(search_rrp->source == RR_QUERY)
  525.         return 0;
  526.  
  527.     /* ensure negative records don't replace older records */
  528.     if(search_rrp->rdlength == 0)
  529.         return -32757;
  530.  
  531.     /* match expired records so that they are replaced */
  532.     if(search_rrp->source != RR_INQUERY){
  533.         if(target_rrp->ttl == 0L)
  534.             return 0;
  535.     }
  536.  
  537.     /* Note: rdlengths are not compared because they vary depending
  538.      * on the representation (ASCII or encoded) this record was
  539.      * generated from.
  540.      */
  541.  
  542.     switch(search_rrp->type){
  543.     case TYPE_A:
  544.         i = search_rrp->rdata.addr != target_rrp->rdata.addr;
  545.         break;
  546.     case TYPE_CNAME:
  547.     case TYPE_MB:
  548.     case TYPE_MG:
  549.     case TYPE_MR:
  550.     case TYPE_NS:
  551.     case TYPE_PTR:
  552.     case TYPE_TXT:
  553.         i = stricmp(search_rrp->rdata.data,target_rrp->rdata.data);
  554.         break;
  555.     case TYPE_HINFO:
  556.         i = strcmp(search_rrp->rdata.hinfo.cpu,target_rrp->rdata.hinfo.cpu) ||
  557.             strcmp(search_rrp->rdata.hinfo.os,target_rrp->rdata.hinfo.os);
  558.         break;
  559.     case TYPE_MX:
  560.         i = stricmp(search_rrp->rdata.mx.exch,target_rrp->rdata.mx.exch);
  561.         break;
  562.     case TYPE_SOA:
  563.         i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
  564.         break;
  565.     default:
  566.         i = -32755;     /* unsupported */
  567.     }
  568.     return i;
  569. }
  570.  
  571. static int
  572. compare_rr_list(rrlp,target_rrp)
  573. register struct rr *rrlp,*target_rrp;
  574. {
  575.     while(rrlp != NULLRR){
  576.         if(compare_rr(rrlp,target_rrp) == 0)
  577.             return 0;
  578. #ifdef DEBUG_PAIN
  579.         if(Dtrace)
  580.             printf("%15d %s\n",
  581.                 compare_rr(rrlp,target_rrp),
  582.                 target_rrp->name);
  583. #endif
  584.         rrlp = rrlp->next;
  585.     }
  586.     return -32767;
  587. }
  588.  
  589. /* Make a new copy of a resource record */
  590. static struct rr *
  591. copy_rr(rrp)
  592. register struct rr *rrp;
  593. {
  594.     register struct rr *newrr;
  595.  
  596.     if(rrp == NULLRR)
  597.         return NULLRR;
  598.  
  599.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  600.     newrr->source = rrp->source;
  601.     newrr->name =   strdup(rrp->name);
  602.     newrr->type =   rrp->type;
  603.     newrr->class =  rrp->class;
  604.     newrr->ttl =    rrp->ttl;
  605.     if(rrp->suffix != NULLCHAR)
  606.         newrr->suffix = strdup(rrp->suffix);
  607.     if((newrr->rdlength = rrp->rdlength) == 0)
  608.         return newrr;
  609.  
  610.     switch(rrp->type){
  611.     case TYPE_A:
  612.         newrr->rdata.addr = rrp->rdata.addr;
  613.         break;
  614.     case TYPE_CNAME:
  615.     case TYPE_MB:
  616.     case TYPE_MG:
  617.     case TYPE_MR:
  618.     case TYPE_NS:
  619.     case TYPE_PTR:
  620.     case TYPE_TXT:
  621.         newrr->rdata.name = strdup(rrp->rdata.name);
  622.         break;
  623.     case TYPE_HINFO:
  624.         newrr->rdata.hinfo.cpu = strdup(rrp->rdata.hinfo.cpu);
  625.         newrr->rdata.hinfo.os = strdup(rrp->rdata.hinfo.os);
  626.         break;
  627.     case TYPE_MX:
  628.         newrr->rdata.mx.pref = rrp->rdata.mx.pref;
  629.         newrr->rdata.mx.exch = strdup(rrp->rdata.mx.exch);
  630.         break;
  631.     case TYPE_SOA:
  632.         newrr->rdata.soa.mname =        strdup(rrp->rdata.soa.mname);
  633.         newrr->rdata.soa.rname =        strdup(rrp->rdata.soa.rname);
  634.         newrr->rdata.soa.serial =       rrp->rdata.soa.serial;
  635.         newrr->rdata.soa.refresh =      rrp->rdata.soa.refresh;
  636.         newrr->rdata.soa.retry =        rrp->rdata.soa.retry;
  637.         newrr->rdata.soa.expire =       rrp->rdata.soa.expire;
  638.         newrr->rdata.soa.minimum =      rrp->rdata.soa.minimum;
  639.         break;
  640.     }
  641.     return newrr;
  642. }
  643.  
  644. static struct rr *
  645. copy_rr_list(rrlp)
  646. register struct rr *rrlp;
  647. {
  648.     register struct rr **rrpp;
  649.     struct rr *result_rrlp;
  650.  
  651.     rrpp = &result_rrlp;
  652.     while(rrlp != NULLRR){
  653.         *rrpp = copy_rr(rrlp);
  654.         rrpp = &(*rrpp)->next;
  655.         rrlp = rrlp->next;
  656.     }
  657.     *rrpp = NULLRR;
  658.     return result_rrlp;
  659. }
  660.  
  661. /* Free (list of) resource records */
  662. void
  663. free_rr(rrlp)
  664. register struct rr *rrlp;
  665. {
  666.     register struct rr *rrp;
  667.  
  668.     while((rrp = rrlp) != NULLRR){
  669.         rrlp = rrlp->next;
  670.  
  671.         free(rrp->comment);
  672.         free(rrp->suffix);
  673.         free(rrp->name);
  674.         if(rrp->rdlength > 0){
  675.             switch(rrp->type){
  676.             case TYPE_A:
  677.                 break;  /* Nothing allocated in rdata section */
  678.             case TYPE_CNAME:
  679.             case TYPE_MB:
  680.             case TYPE_MG:
  681.             case TYPE_MR:
  682.             case TYPE_NS:
  683.             case TYPE_PTR:
  684.             case TYPE_TXT:
  685.                 free(rrp->rdata.name);
  686.                 break;
  687.             case TYPE_HINFO:
  688.                 free(rrp->rdata.hinfo.cpu);
  689.                 free(rrp->rdata.hinfo.os);
  690.                 break;
  691.             case TYPE_MX:
  692.                 free(rrp->rdata.mx.exch);
  693.                 break;
  694.             case TYPE_SOA:
  695.                 free(rrp->rdata.soa.mname);
  696.                 free(rrp->rdata.soa.rname);
  697.                 break;
  698.             }
  699.         }
  700.         free((char *)rrp);
  701.     }
  702. }
  703.  
  704. static struct rr *
  705. make_rr(source,dname,dclass,dtype,ttl,rdl,data)
  706. int source;
  707. char *dname;
  708. int16 dclass;
  709. int16 dtype;
  710. int32 ttl;
  711. int16 rdl;
  712. void *data;
  713. {
  714.     register struct rr *newrr;
  715.  
  716.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  717.     newrr->source = source;
  718.     newrr->name = strdup(dname);
  719.     newrr->class = dclass;
  720.     newrr->type = dtype;
  721.     newrr->ttl = ttl;
  722.     if((newrr->rdlength = rdl) == 0)
  723.         return newrr;
  724.  
  725.     switch(dtype){
  726.     case TYPE_A:
  727.       {
  728.         register int32 *ap = (int32 *)data;
  729.         newrr->rdata.addr = *ap;
  730.         break;
  731.       }
  732.     case TYPE_CNAME:
  733.     case TYPE_MB:
  734.     case TYPE_MG:
  735.     case TYPE_MR:
  736.     case TYPE_NS:
  737.     case TYPE_PTR:
  738.     case TYPE_TXT:
  739.       {
  740.         newrr->rdata.name = strdup((char *)data);
  741.         break;
  742.       }
  743.     case TYPE_HINFO:
  744.       {
  745.         register struct hinfo *hinfop = (struct hinfo *)data;
  746.         newrr->rdata.hinfo.cpu = strdup(hinfop->cpu);
  747.         newrr->rdata.hinfo.os = strdup(hinfop->os);
  748.         break;
  749.       }
  750.     case TYPE_MX:
  751.       {
  752.         register struct mx *mxp = (struct mx *)data;
  753.         newrr->rdata.mx.pref = mxp->pref;
  754.         newrr->rdata.mx.exch = strdup(mxp->exch);
  755.         break;
  756.       }
  757.     case TYPE_SOA:
  758.       {
  759.         register struct soa *soap = (struct soa *)data;
  760.         newrr->rdata.soa.mname =        strdup(soap->mname);
  761.         newrr->rdata.soa.rname =        strdup(soap->rname);
  762.         newrr->rdata.soa.serial =       soap->serial;
  763.         newrr->rdata.soa.refresh =      soap->refresh;
  764.         newrr->rdata.soa.retry =        soap->retry;
  765.         newrr->rdata.soa.expire =       soap->expire;
  766.         newrr->rdata.soa.minimum =      soap->minimum;
  767.         break;
  768.       }
  769.     }
  770.     return newrr;
  771. }
  772.  
  773.  
  774. /**
  775.  **     Domain Cache Utilities
  776.  **/
  777.  
  778. static void
  779. dcache_add(rrlp)
  780. register struct rr *rrlp;
  781. {
  782.     register struct rr *last_rrp;
  783.     struct rr *save_rrp;
  784.  
  785.     if(rrlp == NULLRR)
  786.         return;
  787.  
  788.     save_rrp = rrlp;
  789.     last_rrp = NULLRR;
  790.     while(rrlp != NULLRR){
  791.         rrlp->last = last_rrp;
  792.         last_rrp = rrlp;
  793.         rrlp = rrlp->next;
  794.     }
  795.     last_rrp->next = Dcache;
  796.     if(Dcache != NULLRR)
  797.         Dcache->last = last_rrp;
  798.     Dcache = save_rrp;
  799. }
  800.  
  801. static void
  802. dcache_drop(rrp)
  803. register struct rr *rrp;
  804. {
  805.     if(rrp->last != NULLRR)
  806.         rrp->last->next = rrp->next;
  807.     else
  808.         Dcache = rrp->next;
  809.     if(rrp->next != NULLRR)
  810.         rrp->next->last = rrp->last;
  811.     rrp->last =
  812.     rrp->next = NULLRR;
  813. }
  814.  
  815. /* Search cache for resource records, removing them from the cache.
  816.  * Also, timeout cache entries, and trim cache to size.
  817.  * (Calling with NULLRR is legal -- will timeout & trim only.)
  818.  * Note that an answer from the cache cannot be authoritative, because
  819.  * we cannot guarantee that all the entries remain from a previous request.
  820.  * Returns RR list, or NULLRR if no record found.
  821.  */
  822. static struct rr *
  823. dcache_search(rrlp)
  824. struct rr *rrlp;
  825. {
  826.     register struct rr *rrp, *test_rrp;
  827.     struct rr **rrpp, *result_rrlp;
  828.     int32 elapsed;
  829.     time_t now;
  830.     int count = 0;
  831.  
  832. #ifdef DEBUG
  833.     if(Dtrace && rrlp != NULLRR){
  834.         printf("dcache_search: searching for %s\n",rrlp->name);
  835.     }
  836. #endif
  837.  
  838.     elapsed = (int32)(time(&now) - Dcache_time);
  839.     Dcache_time = now;
  840.  
  841.     rrpp = &result_rrlp;
  842.     for(rrp = Dcache; (test_rrp = rrp) != NULLRR;){
  843.         rrp = rrp->next;
  844.                     /* timeout entries */
  845.         if(test_rrp->ttl > 0L
  846.         && (test_rrp->ttl -= elapsed) <= 0L)
  847.             test_rrp->ttl = 0L;
  848.  
  849.         if(compare_rr_list(rrlp,test_rrp) == 0){
  850.             dcache_drop( *rrpp = test_rrp );
  851.             rrpp = &(*rrpp)->next;
  852.         } else if(test_rrp->source == RR_FILE && ++count > Dcache_size){
  853.             dcache_drop(test_rrp);
  854.             free_rr(test_rrp);
  855.         }
  856.     }
  857.     *rrpp = NULLRR;
  858.     return result_rrlp;
  859. }
  860.  
  861. /* Move a list of resource records to the cache, removing duplicates. */
  862. static void
  863. dcache_update(rrlp)
  864. register struct rr *rrlp;
  865. {
  866.     if(rrlp == NULLRR)
  867.         return;
  868.  
  869.     free_rr(dcache_search(rrlp));   /* remove duplicates, first */
  870.     dcache_add(rrlp);
  871. }
  872.  
  873.  
  874. /**
  875.  **     File Utilities
  876.  **/
  877.  
  878. static struct rr *
  879. get_rr(fp,lastrrp)
  880. FILE *fp;
  881. struct rr *lastrrp;
  882. {
  883. #ifdef M_UNIX
  884. /* fouled up system prototypes.  someone please teach SCO ANSI C, d*mmit!!! */
  885. #define _S_const
  886. #else
  887. #define _S_const const
  888. #endif
  889.     char *line,*lp,*strtok __ARGS((char *,_S_const char *));
  890.     char *getline __ARGS((FILE *));
  891.     struct rr *rrp;
  892.     char *name,*ttl,*class,*type,*data;
  893.     int i;
  894.  
  895. #ifdef __GNUC__
  896.     data = 0;        /* avoid "uninitialized" warning */
  897. #endif
  898. #ifdef notdef
  899.     line = mallocw(256);
  900.     if(fgets(line,256,fp) == NULL){
  901.         free(line);
  902.         return NULLRR;
  903.     }
  904. #else
  905.     line = getline(fp);
  906.     if(line == NULLCHAR)            /* eof or error */
  907.         return NULLRR;
  908. #endif
  909.  
  910.     rrp = (struct rr *)callocw(1,sizeof(struct rr));
  911.     rrp->source = RR_FILE;
  912.  
  913. #ifdef notdef
  914.     /* This is handled in getline() */
  915.     if(line[0] == '\0' || line[0] == '#' || line[0] == ';'){
  916.         rrp->comment = line;
  917.         return rrp;
  918.     }
  919. #endif
  920.  
  921.     if(line[0] == '$') {
  922.         data = strtok(line,delim);
  923.         if(strnicmp(data,"$origin",7) == 0) {
  924.             data = strtok(NULLCHAR,delim);
  925.             rrp->suffix = strdup(data);
  926.             rrp->comment = strdup(line);
  927.             rrp->type = TYPE_MISSING;
  928.             free(line);
  929.             return rrp;
  930.         }
  931.     } else {
  932.         if(lastrrp != NULLRR)
  933.             if(lastrrp->suffix != NULLCHAR)
  934.                 rrp->suffix = strdup(lastrrp->suffix);
  935.     }
  936.  
  937.     if(!isspace(line[0]) || lastrrp == NULLRR){
  938.         name = strtok(line,delim);
  939.         lp = NULLCHAR;
  940.     } else {        /* Name field is missing */
  941.         name = lastrrp->name;
  942.         lp = line;
  943.     }
  944. #ifdef notdef
  945.     if(name == NULLCHAR || (name != NULLCHAR && (i = strlen(name)) == 0)){
  946.         rrp->comment = strdup("\n");
  947.         free(line);
  948.         return rrp;
  949.     }
  950. #endif
  951.  
  952.     if(name[0] == '@') {
  953.         if(rrp->suffix != NULLCHAR)
  954.             name = rrp->suffix;
  955.         else
  956.             if(Dsuffix != NULLCHAR)
  957.                 name = Dsuffix;
  958.             else
  959.                 name = "ampr.org.";
  960.     }
  961.  
  962.     i=strlen(name);
  963.     if(name[i-1] != '.'){
  964.         /* Tack on the current domain suffix if defined */
  965.         if(rrp->suffix != NULLCHAR && Dsuffix != NULLCHAR) {
  966.             rrp->name = mallocw(i+strlen(rrp->suffix)+2);
  967.             sprintf(rrp->name,"%s.%s",name,rrp->suffix);
  968.         } else {
  969.         /* Tack on a trailing period if it's not there */
  970.             rrp->name = mallocw((unsigned)i+2);
  971.             strcpy(rrp->name,name);
  972.             strcat(rrp->name,".");
  973.         }
  974.     } else
  975.         /* fully qualified domain name */
  976.         rrp->name = strdup(name);
  977.  
  978.     ttl = strtok(lp,delim);
  979.  
  980.     if(ttl == NULLCHAR || (!isdigit(ttl[0]) && ttl[0] != '-')){
  981.         /* Optional ttl field is missing */
  982.         rrp->ttl = TTL_MISSING;
  983.         class = ttl;
  984.     } else {
  985.         rrp->ttl = atol(ttl);
  986.         class = strtok(NULLCHAR,delim);
  987.     }
  988.  
  989.     if(class == NULLCHAR){
  990.         /* we're in trouble, but keep processing */
  991.         rrp->class = CLASS_MISSING;
  992.         type = class;
  993.     } else if(class[0] == '<'){
  994.         rrp->class = atoi(&class[1]);
  995.         type = strtok(NULLCHAR,delim);
  996.     } else if(stricmp(class,"IN") == 0){
  997.         rrp->class = CLASS_IN;
  998.         type = strtok(NULLCHAR,delim);
  999.     } else {
  1000.         /* Optional class field is missing; assume IN */
  1001.         rrp->class = CLASS_IN;
  1002.         type = class;
  1003.     }
  1004.  
  1005.     if(type == NULLCHAR){
  1006.         /* we're in trouble, but keep processing */
  1007.         rrp->type = TYPE_MISSING;
  1008.         data = type;
  1009.     } else if(type[0] == '{'){
  1010.         rrp->type = atoi(&class[1]);
  1011.         data = strtok(NULLCHAR,delim);
  1012.     } else {
  1013.         rrp->type = TYPE_MISSING;
  1014.     for(i=1;i<NDTYPES;i++){
  1015.             if(stricmp(type,Dtypes[i]) == 0){
  1016.                 rrp->type = i;
  1017.                 data = strtok(NULLCHAR,delim);
  1018.                 break;
  1019.             }
  1020.         }
  1021.     }
  1022.  
  1023.     if(rrp->type == TYPE_MISSING){
  1024.         data = NULLCHAR;
  1025.     }
  1026.  
  1027.     if(data == NULLCHAR){
  1028.         /* Empty record, just return */
  1029.         free(line);
  1030.         return rrp;
  1031.     }
  1032.     switch(rrp->type){
  1033.     case TYPE_A:
  1034.         rrp->rdlength = 4;
  1035.         rrp->rdata.addr = aton(data);
  1036.         break;
  1037.     case TYPE_CNAME:
  1038.     case TYPE_MB:
  1039.     case TYPE_MG:
  1040.     case TYPE_MR:
  1041.     case TYPE_NS:
  1042.     case TYPE_PTR:
  1043.     case TYPE_TXT:
  1044.         rrp->rdlength = strlen(data);
  1045.         rrp->rdata.name = strdup(data);
  1046.         break;
  1047.     case TYPE_HINFO:
  1048.         rrp->rdlength = strlen(data);
  1049.         rrp->rdata.hinfo.cpu = strdup(data);
  1050.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1051.             rrp->rdlength += strlen(data);
  1052.             rrp->rdata.hinfo.os = strdup(data);
  1053.         }
  1054.         break;
  1055.     case TYPE_MX:
  1056.         rrp->rdata.mx.pref = atoi(data);
  1057.         rrp->rdlength = 2;
  1058.  
  1059.         /* Get domain name of exchanger */
  1060.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1061.             rrp->rdlength += strlen(data);
  1062.             rrp->rdata.mx.exch = strdup(data);
  1063.         }
  1064.         break;
  1065.     case TYPE_SOA:
  1066.         /* Get domain name of master name server */
  1067.         rrp->rdlength = strlen(data);
  1068.         rrp->rdata.soa.mname = strdup(data);
  1069.  
  1070.         /* Get domain name of irresponsible person */
  1071.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1072.             rrp->rdata.soa.rname = strdup(data);
  1073.             rrp->rdlength += strlen(data);
  1074.         }
  1075.         data = strtok(NULLCHAR,delim);
  1076.         rrp->rdata.soa.serial = atol(data);
  1077.         data = strtok(NULLCHAR,delim);
  1078.         rrp->rdata.soa.refresh = atol(data);
  1079.         data = strtok(NULLCHAR,delim);
  1080.         rrp->rdata.soa.retry = atol(data);
  1081.         data = strtok(NULLCHAR,delim);
  1082.         rrp->rdata.soa.expire = atol(data);
  1083.         data = strtok(NULLCHAR,delim);
  1084.         rrp->rdata.soa.minimum = atol(data);
  1085.         rrp->rdlength += 20;
  1086.         break;
  1087.     }
  1088.  
  1089.     /* !!! need to handle trailing comments */
  1090.     free(line);
  1091.     return rrp;
  1092. }
  1093.  
  1094. /* Print a resource record */
  1095. static void
  1096. put_rr(fp,rrp)
  1097. FILE *fp;
  1098. struct rr *rrp;
  1099. {
  1100.     int trans;
  1101.  
  1102.     if(fp == NULLFILE || rrp == NULLRR)
  1103.         return;
  1104.  
  1105.     if(rrp->name == NULLCHAR && rrp->comment != NULLCHAR){
  1106.         fprintf(fp,"%s",rrp->comment);
  1107.         return;
  1108.     }
  1109.  
  1110.     fprintf(fp,"%s",rrp->name);
  1111.     if(rrp->ttl != TTL_MISSING)
  1112.         fprintf(fp,"\t%ld",rrp->ttl);
  1113.     if(rrp->class == CLASS_IN)
  1114.         fprintf(fp,"\tIN");
  1115.     else
  1116.         fprintf(fp,"\t<%u>",rrp->class);
  1117.     if(rrp->type < NDTYPES)
  1118.         fprintf(fp,"\t%s",Dtypes[rrp->type]);
  1119.     else
  1120.         fprintf(fp,"\t{%u}",rrp->type);
  1121.     if(rrp->rdlength == 0){
  1122.         /* Null data portion, indicates nonexistent record */
  1123.         /* or unsupported type.  Hopefully, these will filter */
  1124.         /* as time goes by. */
  1125.         fprintf(fp," (null rr?)\n");
  1126.         return;
  1127.     }
  1128.     switch(rrp->type){
  1129.     case TYPE_A:
  1130.         trans = DTranslate;             /* Save IP address translation state */
  1131.         DTranslate = 0;                 /* Force output to be numeric IP addr */
  1132.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  1133.         DTranslate = trans;             /* Restore original state */
  1134.         break;
  1135.     case TYPE_CNAME:
  1136.     case TYPE_MB:
  1137.     case TYPE_MG:
  1138.     case TYPE_MR:
  1139.     case TYPE_NS:
  1140.     case TYPE_PTR:
  1141.     case TYPE_TXT:
  1142.         /* These are all printable text strings */
  1143.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  1144.         break;
  1145.     case TYPE_HINFO:
  1146.         fprintf(fp,"\t%s\t%s\n",
  1147.          rrp->rdata.hinfo.cpu,
  1148.          rrp->rdata.hinfo.os);
  1149.         break;
  1150.     case TYPE_MX:
  1151.         fprintf(fp,"\t%u\t%s\n",
  1152.          rrp->rdata.mx.pref,
  1153.          rrp->rdata.mx.exch);
  1154.         break;
  1155.     case TYPE_SOA:
  1156.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  1157.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  1158.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  1159.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  1160.          rrp->rdata.soa.minimum);
  1161.         break;
  1162.     default:
  1163.         fprintf(fp," (unknown format)\n");
  1164.         break;
  1165.     }
  1166. }
  1167.  
  1168. /* Search local database for resource records.
  1169.  * Returns RR list, or NULLRR if no record found.
  1170.  */
  1171. static struct rr *
  1172. dfile_search(rrlp)
  1173. struct rr *rrlp;
  1174. {
  1175.     register struct rr *frrp;
  1176.     struct rr **rrpp, *result_rrlp, *oldrrp;
  1177.     int32 elapsed;
  1178.     FILE *dbase;
  1179.     struct stat dstat;
  1180.  
  1181. #ifdef DEBUG
  1182.     if(Dtrace){
  1183.         printf("dfile_search: searching for %s\n",rrlp->name);
  1184.     }
  1185. #endif
  1186.  
  1187.     while(Dfile_writing > 0)
  1188.         pwait(&Dfile_reading);
  1189.     Dfile_reading++;
  1190.  
  1191.     if((dbase = fopen(Dfile,READ_TEXT)) == NULLFILE){
  1192.         Dfile_reading--;
  1193.         return NULLRR;
  1194.     }
  1195.     if(fstat(fileno(dbase),&dstat) != 0){
  1196.         tprintf("dfile_search: can't get file status\n");
  1197.         fclose(dbase);
  1198.         Dfile_reading--;
  1199.         return NULLRR;
  1200.     }
  1201.     if((elapsed = (int32)(Dcache_time - (time_t)dstat.st_ctime)) < 0L)
  1202.         elapsed = -elapsed;     /* arbitrary time mismatch */
  1203.  
  1204.     result_rrlp = NULLRR;           /* for contiguous test below */
  1205.     oldrrp = NULLRR;
  1206.     rrpp = &result_rrlp;
  1207.     while((frrp = get_rr(dbase,oldrrp)) != NULLRR){
  1208.         free_rr(oldrrp);
  1209.         if(frrp->type != TYPE_MISSING
  1210.         && frrp->rdlength > 0
  1211.         && compare_rr_list(rrlp,frrp) == 0){
  1212.             if(frrp->ttl > 0L
  1213.             && (frrp->ttl -= elapsed) <= 0L)
  1214.                 frrp->ttl = 0L;
  1215.             *rrpp = frrp;
  1216.             rrpp = &(*rrpp)->next;
  1217.             oldrrp = copy_rr(frrp);
  1218.         } else {
  1219.             oldrrp = frrp;
  1220.             /*
  1221.                 All records of the same name and the same type
  1222.                 are contiguous.  Therefore, for a single query,
  1223.                 we can stop searching.  Multiple queries must
  1224.                 read the whole file.
  1225.             */
  1226.             if(rrlp->next == NULLRR && result_rrlp != NULLRR){
  1227.                 break;
  1228.             }
  1229.         }
  1230.         if(!main_exit)
  1231.             pwait(NULL);    /* run multiple sessions */
  1232.     }
  1233.     free_rr(oldrrp);
  1234.     *rrpp = NULLRR;
  1235.  
  1236.     fclose(dbase);
  1237.  
  1238.     if(--Dfile_reading <= 0){
  1239.         Dfile_reading = 0;
  1240.         psignal(&Dfile_writing,0);
  1241.     }
  1242.  
  1243.     return result_rrlp;
  1244. }
  1245.  
  1246. /* Process which will add new resource records from the cache
  1247.  * to the local file, eliminating duplicates while it goes.
  1248.  */
  1249. static void
  1250. dfile_update(s,unused,p)
  1251. int s;
  1252. void *unused;
  1253. void *p;
  1254. {
  1255.     struct rr **rrpp, *rrlp, *oldrrp;
  1256.     char *newname;
  1257.     FILE *old_fp, *new_fp;
  1258.     struct stat old_stat, new_stat;
  1259.  
  1260.     log(-1,"update Domain.txt initiated");
  1261.  
  1262.     close_s(Curproc->input);
  1263.     Curproc->input = -1;
  1264.     close_s(Curproc->output);
  1265.     Curproc->output = -1;
  1266.  
  1267.     newname = strdup(Dfile);
  1268.     strcpy(&newname[strlen(newname)-3],"tmp");
  1269.  
  1270.     while(Dfile_wait_absolute != 0L && !main_exit){
  1271.         register struct rr *frrp;
  1272.         int32 elapsed;
  1273.  
  1274.         while(Dfile_wait_absolute != 0L){
  1275.             elapsed = Dfile_wait_absolute - secclock();
  1276.             Dfile_wait_absolute = 0L;
  1277.             if(elapsed > 0L && !main_exit){
  1278.                 alarm(elapsed*1000L);
  1279.                 pwait(&Dfile_wait_absolute);
  1280.                 alarm(0L);
  1281.             }
  1282.         }
  1283.  
  1284.         log(-1,"update Domain.txt");
  1285.  
  1286.         /* create new file for copy */
  1287.         if((new_fp = fopen(newname,WRITE_TEXT)) == NULLFILE){
  1288.             printf("dfile_update: can't create %s!\n",newname);
  1289.             break;
  1290.         }
  1291.         if(fstat(fileno(new_fp),&new_stat) != 0){
  1292.             printf("dfile_update: can't get new_file status!\n");
  1293.             fclose(new_fp);
  1294.             break;
  1295.         }
  1296.  
  1297.         pwait(NULL);    /* file operations can be slow */
  1298.  
  1299.         /* timeout the cache one last time before writing */
  1300.         (void)dcache_search(NULLRR);
  1301.  
  1302.         /* copy new RRs out to the new file */
  1303.         /* (can't wait here, the cache might change) */
  1304.         rrpp = &rrlp;
  1305.         for(frrp = Dcache; frrp != NULLRR; frrp = frrp->next ){
  1306.             switch(frrp->source){
  1307.             case RR_QUESTION:
  1308.             case RR_ANSWER:
  1309.             case RR_AUTHORITY:
  1310.             case RR_ADDITIONAL:
  1311.                 *rrpp = copy_rr(frrp);
  1312.                 if(frrp->type != TYPE_MISSING
  1313.                 && frrp->rdlength > 0)
  1314.                     put_rr(new_fp,frrp);
  1315.                 rrpp = &(*rrpp)->next;
  1316.                 frrp->source = RR_FILE;
  1317.                 break;
  1318.             }
  1319.         }
  1320.         *rrpp = NULLRR;
  1321.  
  1322.         /* open up the old file, concurrently with everyone else */
  1323.         if((old_fp = fopen(Dfile,READ_TEXT)) == NULLFILE){
  1324.             /* great! no old file, so we're ready to go. */
  1325.             fclose(new_fp);
  1326.             rename(newname,Dfile);
  1327.             free_rr(rrlp);
  1328.             break;
  1329.         }
  1330.         if(fstat(fileno(old_fp),&old_stat) != 0){
  1331.             printf("dfile_update: can't get old_file status!\n");
  1332.             fclose(new_fp);
  1333.             fclose(old_fp);
  1334.             free_rr(rrlp);
  1335.             break;
  1336.         }
  1337.         if((elapsed = (int32)(new_stat.st_ctime - old_stat.st_ctime)) < 0L)
  1338.             elapsed = -elapsed;     /* file times are inconsistant */
  1339.  
  1340.         /* Now append any non-duplicate records */
  1341.         oldrrp = NULLRR;
  1342.         while((frrp = get_rr(old_fp,oldrrp)) != NULLRR){
  1343.             free_rr(oldrrp);
  1344.             if(frrp->name == NULLCHAR
  1345.             && frrp->comment != NULLCHAR)
  1346.                 put_rr(new_fp,frrp);
  1347.             if(frrp->type != TYPE_MISSING
  1348.             && frrp->rdlength > 0
  1349.             && compare_rr_list(rrlp,frrp) != 0){
  1350.                 if(frrp->ttl > 0L
  1351.                 && (frrp->ttl -= elapsed) <= 0L)
  1352.                     frrp->ttl = 0L;
  1353.                 if(frrp->ttl != 0 || !Dfile_clean)
  1354.                     put_rr(new_fp,frrp);
  1355.             }
  1356.             oldrrp = frrp;
  1357.             if(!main_exit)
  1358.                 pwait(NULL);    /* run in background */
  1359.         }
  1360.         free_rr(oldrrp);
  1361.         fclose(new_fp);
  1362.         fclose(old_fp);
  1363.         free_rr(rrlp);
  1364.  
  1365.         /* wait for everyone else to finish reading */
  1366.         Dfile_writing++;
  1367.         while(Dfile_reading > 0)
  1368.             pwait(&Dfile_writing);
  1369.  
  1370.         unlink(Dfile);
  1371.         rename(newname,Dfile);
  1372.  
  1373.         Dfile_writing = 0;
  1374.         psignal(&Dfile_reading,0);
  1375.     }
  1376.     free(newname);
  1377.  
  1378.     log(-1,"update Domain.txt finished");
  1379.     Dfile_updater = NULLPROC;
  1380. }
  1381.  
  1382.  
  1383. /**
  1384.  **     Domain Server Utilities
  1385.  **/
  1386.  
  1387. static void
  1388. dumpdomain(dhp,rtt)
  1389. struct dhdr *dhp;
  1390. int32 rtt;
  1391. {
  1392.     struct rr *rrp;
  1393.  
  1394.  
  1395.     printf("response id %u (rtt %lu ms) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  1396.      dhp->id,rtt,
  1397.      dhp->qr,dhp->opcode,dhp->aa,dhp->tc,dhp->rd,
  1398.      dhp->ra,dhp->rcode);
  1399.     printf("%u questions:\n",dhp->qdcount);
  1400.     for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next){
  1401.         printf("%s type %s class %u\n",rrp->name,
  1402.          Dtypes[rrp->type],rrp->class);
  1403.     }
  1404.     printf("%u answers:\n",dhp->ancount);
  1405.     for(rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next){
  1406.         put_rr(stdout,rrp);
  1407.     }
  1408.     printf("%u authority:\n",dhp->nscount);
  1409.     for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1410.         put_rr(stdout,rrp);
  1411.     }
  1412.     printf("%u additional:\n",dhp->arcount);
  1413.     for(rrp = dhp->additional; rrp != NULLRR; rrp = rrp->next){
  1414.         put_rr(stdout,rrp);
  1415.     }
  1416. #ifndef UNIX
  1417.     fflush(stdout);
  1418. #endif
  1419. }
  1420.  
  1421. static int
  1422. dns_makequery(op,srrp,buffer,buflen)
  1423. int16 op;       /* operation */
  1424. struct rr *srrp;/* Search RR */
  1425. char *buffer;   /* Area for query */
  1426. int16 buflen;   /* Length of same */
  1427. {
  1428.     char *cp,*cp1;
  1429.     char *dname, *sname;
  1430.     int16 parameter;
  1431.     int16 dlen,len;
  1432.  
  1433.     cp = buffer;
  1434.     /* Use millisecond clock for timestamping */
  1435.     cp = put16(cp,(int16)msclock());
  1436.     parameter = (op << 11)
  1437.             | 0x0100;       /* Recursion desired */
  1438.     cp = put16(cp,parameter);
  1439.     cp = put16(cp,1);
  1440.     cp = put16(cp,0);
  1441.     cp = put16(cp,0);
  1442.     cp = put16(cp,0);
  1443.  
  1444.     sname = strdup(srrp->name);
  1445.     dname = sname;
  1446.     dlen = strlen(dname);
  1447.     for(;;){
  1448.         /* Look for next dot */
  1449.         cp1 = strchr(dname,'.');
  1450.         if(cp1 != NULLCHAR)
  1451.             len = cp1-dname;        /* More to come */
  1452.         else
  1453.             len = dlen;     /* Last component */
  1454.         *cp++ = len;            /* Write length of component */
  1455.         if(len == 0)
  1456.             break;
  1457.         /* Copy component up to (but not including) dot */
  1458.         strncpy(cp,dname,(size_t)len);
  1459.         cp += len;
  1460.         if(cp1 == NULLCHAR){
  1461.             *cp++ = 0;      /* Last one; write null and finish */
  1462.             break;
  1463.         }
  1464.         dname += len+1;
  1465.         dlen -= len+1;
  1466.     }
  1467.     free(sname);
  1468.     cp = put16(cp,srrp->type);
  1469.     cp = put16(cp,srrp->class);
  1470.     return cp - buffer;
  1471. }
  1472.  
  1473. /* domain server resolution loop
  1474.  * returns: any answers in cache.
  1475.  *      (future features)
  1476.  *      multiple queries.
  1477.  *      inverse queries.
  1478.  */
  1479. static void
  1480. dns_query(rrlp)
  1481. struct rr *rrlp;
  1482. {
  1483.     struct mbuf *bp;
  1484.     struct dhdr *dhp;
  1485.     struct dserver *dp;     /* server list */
  1486.     int32 rtt,abserr;
  1487.     int tried = 0;          /* server list has been retried (count) */
  1488.  
  1489.     if((dp = Dservers) == NULLDOM){
  1490.         return;
  1491.     }
  1492.  
  1493.     if(!Mprunning)
  1494.         return;
  1495.  
  1496.     for(;;){
  1497.         char *buf;
  1498.         int len;
  1499.         struct sockaddr_in server_in;
  1500.         int s;
  1501.         int rval;
  1502.  
  1503.         dp->queries++;
  1504.  
  1505.         s = socket(AF_INET,SOCK_DGRAM,0);
  1506.         server_in.sin_family = AF_INET;
  1507.         server_in.sin_port = IPPORT_DOMAIN;
  1508.         server_in.sin_addr.s_addr = dp->address;
  1509.  
  1510.         if(Dtrace){
  1511.             printf("dns_query: querying server %s for %s\n",
  1512.              inet_ntoa(dp->address),rrlp->name);
  1513.         }
  1514.  
  1515.         buf = mallocw(512);
  1516.         len = dns_makequery(0,rrlp,buf,512);
  1517.         sendto(s,buf,len,0,(char *)&server_in,sizeof(server_in));
  1518.         free(buf);
  1519.         alarm(max(dp->timeout,100));
  1520.         /* Wait for something to happen */
  1521.         rval = recv_mbuf(s,&bp,0,NULLCHAR,0);
  1522.         alarm(0L);
  1523.         close_s(s);
  1524.  
  1525.         if(Dtrace){
  1526.             printf("dns_query: received message length %d, errno %d\n", rval, errno );
  1527.         }
  1528.  
  1529.         if(rval > 0)
  1530.             break;
  1531.  
  1532.         if(errno == EABORT){
  1533.             return;         /* Killed by "reset" command */
  1534.         }
  1535.  
  1536.         /* Timeout; back off this one and try another server */
  1537.         dp->timeouts++;
  1538.         dp->timeout <<= 1;
  1539.  
  1540.         /* But we must have some sort of sensible limit - surely? */
  1541.         if(dp->timeout > (Dserver_maxwait * 1000L)){
  1542.             dp->timeout = Dserver_maxwait * 1000L;
  1543.         }
  1544.  
  1545.         if((dp = dp->next) == NULLDOM){
  1546.             dp = Dservers;
  1547.             if(Dserver_retries > 0 && ++tried > Dserver_retries)
  1548.                 return;
  1549.         }
  1550.     }
  1551.  
  1552.     /* got a response */
  1553.     dp->responses++;
  1554.     dhp = (struct dhdr *) mallocw(sizeof(struct dhdr));
  1555.     ntohdomain(dhp,&bp);    /* Convert to local format */
  1556.  
  1557.     /* Compute and update the round trip time */
  1558.     rtt = (int32) ((int16)msclock() - dhp->id);
  1559.     abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  1560.     dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  1561.     dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  1562.     dp->timeout = 4 * dp->mdev + dp->srtt;
  1563.  
  1564.     /* move to top of list for next time */
  1565.     if(dp->prev != NULLDOM){
  1566.         dlist_drop(dp);
  1567.         dlist_add(dp);
  1568.     }
  1569.  
  1570.     if(Dtrace)
  1571.         dumpdomain(dhp,rtt);
  1572.  
  1573.     /* Add negative reply to answers.  This assumes that there was
  1574.      * only one question, which is true for all questions we send.
  1575.      */
  1576.     if(dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)){
  1577.         register struct rr *rrp;
  1578.         long ttl = 600L; /* Default TTL for negative records */
  1579.  
  1580.         /* look for SOA ttl */
  1581.         for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1582.             if(rrp->type == TYPE_SOA)
  1583.                 ttl = rrp->ttl;
  1584.         }
  1585.  
  1586.         /* make the questions the negative answers */
  1587.         for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
  1588.             rrp->ttl = ttl;
  1589.     } else {
  1590.         free_rr(dhp->questions);
  1591.         dhp->questions = NULLRR;
  1592.     }
  1593.  
  1594.     /* post in reverse order to maintain original order */
  1595.     dcache_update(dhp->additional);
  1596.     dcache_update(dhp->authority);
  1597.     dcache_update(dhp->answers);
  1598.     dcache_update(dhp->questions);
  1599.  
  1600.     Dfile_wait_absolute = secclock() + Dfile_wait_relative;
  1601.     if(Dfile_updater == NULLPROC){
  1602.         Dfile_updater = newproc("domain update",
  1603.             512,dfile_update,0,NULL,NULL,0);
  1604.     }
  1605.  
  1606. #ifdef DEBUG
  1607.     if(Dtrace)
  1608.         keywait(NULLCHAR,1);    /* so we can look around */
  1609. #endif
  1610.     free((char *)dhp);
  1611.     return;
  1612. }
  1613.  
  1614.  
  1615. /**
  1616.  **     Resolver Utilities
  1617.  **/
  1618.  
  1619. /* Return TRUE if string appears to be an IP address in dotted decimal;
  1620.  * return FALSE otherwise (i.e., if string is a domain name)
  1621.  */
  1622. static int
  1623. isaddr(s)
  1624. register char *s;
  1625. {
  1626.     char c;
  1627.  
  1628.     if(s == NULLCHAR)
  1629.         return TRUE;       /* Can't happen */
  1630.  
  1631.     while((c = *s++) != '\0'){
  1632.         if(c != '[' && c != ']' && !isdigit(c) && c != '.')
  1633.             return FALSE;
  1634.     }
  1635.     return TRUE;
  1636. }
  1637.  
  1638. /* Search for resource records.
  1639.  * Returns RR list, or NULLRR if no record found.
  1640.  */
  1641. static struct rr *
  1642. resolver(rrlp)
  1643. register struct rr *rrlp;
  1644. {
  1645.     register struct rr *result_rrlp;
  1646.  
  1647.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  1648.         result_rrlp = dfile_search(rrlp);
  1649.     }
  1650.     if(result_rrlp == NULLRR || check_ttl(result_rrlp) != 0){
  1651.         dcache_add(result_rrlp);        /* save any expired RRs */
  1652.         dns_query(rrlp);
  1653.         result_rrlp = dcache_search(rrlp);
  1654.     }
  1655.     dcache_add(copy_rr_list(result_rrlp));
  1656.     return result_rrlp;
  1657. }
  1658.  
  1659. /* general entry point for address -> domain name resolution.
  1660.  * Returns RR list, or NULLRR if no record found.
  1661.  */
  1662. struct rr *
  1663. inverse_a(ip_address)
  1664. int32 ip_address;
  1665. {
  1666.     struct rr *prrp;
  1667.     struct rr *result_rrlp;
  1668.     char pname[30];
  1669.  
  1670.     if(ip_address == 0L)
  1671.         return NULLRR;
  1672.  
  1673.     sprintf( pname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
  1674.             lobyte(loword(ip_address)),
  1675.             hibyte(loword(ip_address)),
  1676.             lobyte(hiword(ip_address)),
  1677.             hibyte(hiword(ip_address)) );
  1678.  
  1679.     prrp = make_rr(RR_QUERY,pname,CLASS_IN,TYPE_PTR,0,0,NULL);
  1680.  
  1681.     prrp->next =            /* make list to speed search */
  1682.         make_rr(RR_INQUERY,NULLCHAR,CLASS_IN,TYPE_A,0,4,&ip_address);
  1683.  
  1684.     result_rrlp = resolver(prrp);
  1685.  
  1686.     free_rr(prrp);
  1687.     return result_rrlp;
  1688. }
  1689.  
  1690. /* general entry point for domain name -> resource resolution.
  1691.  * Returns RR list, or NULLRR if no record found.
  1692.  */
  1693. /* Optional recursive search to resolve CNAME records that
  1694.    prevents proper handling of CNAME queries.  Forces recursion to take
  1695.    place only at the resolver of the node originating the query.
  1696.    Modification introducted by Don Sandstrom, KG7CP, October 15, 1992.
  1697.    Additional mod by WG7J .
  1698.    */
  1699.  
  1700. struct rr *
  1701. resolve_rr(dname,dtype,recurse)
  1702. char *dname;
  1703. int16 dtype;
  1704. int recurse;
  1705. {
  1706.     struct rr *qrrp;
  1707.     struct rr *result_rrlp;
  1708.     char *sname;
  1709.     int looping;
  1710.  
  1711.     if(dname == NULLCHAR)
  1712.         return NULLRR;
  1713.  
  1714.     sname = domainsuffix(dname);
  1715.     qrrp = make_rr(RR_QUERY,sname,CLASS_IN,dtype,0,0,NULL);
  1716.     free(sname);
  1717.  
  1718.     if(!recurse) {
  1719.     result_rrlp = resolver(qrrp);
  1720. #ifdef DEBUG
  1721.         if(Dtrace)
  1722.             put_rr(stdout,result_rrlp);
  1723. #endif
  1724.     } else {
  1725.     looping = MAXCNAME;
  1726.     while(looping > 0){
  1727.         if((result_rrlp=resolver(qrrp)) == NULLRR
  1728.         || result_rrlp->type == dtype)
  1729.         break;
  1730. #ifdef DEBUG
  1731.         if(Dtrace)
  1732.         put_rr(stdout,result_rrlp);
  1733. #endif
  1734.         /* Should be CNAME or PTR record */
  1735.         /* Replace name and try again */
  1736.         free(qrrp->name);
  1737.         qrrp->name = strdup(result_rrlp->rdata.name);
  1738.         free_rr(result_rrlp);
  1739.         result_rrlp = NULLRR;
  1740.         looping--;
  1741.     }
  1742.     }
  1743.     free_rr(qrrp);
  1744.     return result_rrlp;
  1745. }
  1746.  
  1747. /* main entry point for address -> domain name resolution.
  1748.  * Returns string, or NULLCHAR if no name found.
  1749.  */
  1750. char *
  1751. resolve_a(ip_address,shorten)
  1752. int32 ip_address;               /* search address */
  1753. int shorten;                    /* return only first part of name (flag)*/
  1754. {
  1755.     struct rr *save_rrlp, *rrlp;
  1756.     char *result = NULLCHAR, *p;
  1757.  
  1758.     for( rrlp = save_rrlp = inverse_a(ip_address);
  1759.          rrlp != NULLRR && result == NULLCHAR;
  1760.          rrlp = rrlp->next ){
  1761.         if(rrlp->rdlength > 0){
  1762.             switch(rrlp->type){
  1763.             case TYPE_PTR:
  1764.                 result = strdup(rrlp->rdata.name);
  1765.                 break;
  1766.             case TYPE_A:
  1767.                 result = strdup(rrlp->name);
  1768.                 break;
  1769.             }
  1770.         }
  1771.     }
  1772.     free_rr(save_rrlp);
  1773.  
  1774. #ifdef notdef
  1775.     if(result != NULLCHAR)
  1776.         result[strlen(result) - 1] = '\0';      /* remove trailing . */
  1777.  
  1778.     if(result != NULLCHAR && shorten){
  1779.         int dot;
  1780.         char *shortened;
  1781.  
  1782.         if((dot = strcspn(result, ".")) != 0){
  1783.             shortened = mallocw(dot+1);
  1784.             strncpy(shortened, result, dot);
  1785.             shortened[dot] = '\0';
  1786.             free(result);
  1787.             result = shortened;
  1788.         }
  1789.     }
  1790. #endif
  1791.  
  1792.     /* From Dennis Goodwin, kb7dz.
  1793.      * when domain verbose is off,
  1794.      * this make a domain name line bbs.wg7j.ampr.org show as bbs.wg7j
  1795.      * as opposed to bbs, as the above code does.
  1796.      */
  1797.      if(result != NULLCHAR && shorten) {
  1798.     if (Dsuffix != NULLCHAR)
  1799.         /* domain name minus domain suffix */
  1800.         p = strstr(result, Dsuffix);
  1801.     else
  1802.         /* domain name up to, and including the first period */
  1803.         p = strchr(result, '.') + 1;
  1804.     if(p != NULLCHAR)
  1805.         *p = '\0';
  1806.     }
  1807.     if(result != NULLCHAR && *result) {
  1808.     /* remove trailing . */
  1809.        for (p=result; *p; ++p)
  1810.      ;
  1811.        if (*(--p) == '.')
  1812.        *p = (char) 0;
  1813.     }
  1814.     /* end of mod */
  1815.  
  1816.     return result;
  1817. }
  1818.  
  1819. /* Main entry point for domain name -> address resolution.
  1820.  * Returns 0 if name is currently unresolvable.
  1821.  */
  1822. int32
  1823. resolve(name)
  1824. char *name;
  1825. {
  1826.     register struct rr *rrlp;
  1827.     int32 ip_address = 0;
  1828.  
  1829.     if(name == NULLCHAR)
  1830.         return 0;
  1831.  
  1832.     if(isaddr(name))
  1833.         return aton(name);
  1834.  
  1835.     if((rrlp = resolve_rr(name,TYPE_A,1)) != NULLRR
  1836.      && rrlp->rdlength > 0)
  1837.         ip_address = rrlp->rdata.addr;
  1838.  
  1839.     /* multi-homed hosts are handled here */
  1840.     if(rrlp != NULLRR && rrlp->next != NULLRR) {
  1841.         register struct rr *rrp;
  1842.         register struct route *rp;
  1843.         int16 cost = MAXINT16;
  1844.         rrp = rrlp;
  1845.         while(rrp != NULLRR) { /* choose the best of a set of routes */
  1846.             if(rrp->rdlength > 0 &&
  1847.                (rp = rt_lookup(rrp->rdata.addr)) != NULLROUTE &&
  1848.                rp->metric <= cost) {
  1849.                 ip_address = rrp->rdata.addr;
  1850.                 cost = rp->metric;
  1851.             }
  1852.             rrp = rrp->next;
  1853.         }
  1854.     }
  1855.  
  1856.     free_rr(rrlp);
  1857.     return ip_address;
  1858. }
  1859.  
  1860.  
  1861. /* Main entry point for MX record lookup.
  1862.  * Returns 0 if name is currently unresolvable.
  1863.  */
  1864. int32
  1865. resolve_mx(name)
  1866. char *name;
  1867. {
  1868.     register struct rr *rrp, *arrp;
  1869.     char *sname, *tmp, *cp;
  1870.     int32 addr, ip_address = 0;
  1871.     int16 pref = MAXINT16;
  1872.  
  1873.     if(name == NULLCHAR)
  1874.         return 0;
  1875.  
  1876.     if(isaddr(name)){
  1877.         if((sname = resolve_a(aton(name),FALSE)) == NULLCHAR)
  1878.             return 0;
  1879.     }
  1880.     else
  1881.         sname = strdup(name);
  1882.  
  1883.     cp = sname;
  1884.     while(1){
  1885.     rrp = arrp = resolve_rr(sname,TYPE_MX,1);
  1886.         /* Search this list of rr's for an MX record */
  1887.         while(rrp != NULLRR){
  1888.             if(rrp->rdlength > 0 && rrp->rdata.mx.pref <= pref &&
  1889.                (addr = resolve(rrp->rdata.mx.exch)) != 0L){
  1890.                 pref = rrp->rdata.mx.pref;
  1891.                 ip_address = addr;
  1892.             }
  1893.             rrp = rrp->next;
  1894.         }
  1895.         free_rr(arrp);
  1896.         if(ip_address != 0)
  1897.             break;
  1898.         /* Compose wild card one level up */
  1899.         if((cp = strchr(cp,'.')) == NULLCHAR)
  1900.             break;
  1901.         tmp = mallocw(strlen(cp)+2);
  1902.         sprintf(tmp,"*%s",cp);          /* wildcard expansion */
  1903.         free(sname);
  1904.         sname = tmp;
  1905.         cp = sname + 2;
  1906.     }
  1907.     free(sname);
  1908.     return ip_address;
  1909. }
  1910.  
  1911. /* Search for local records of the MB, MG and MR type. Returns list of
  1912.  * matching records.
  1913.  */
  1914. struct rr *
  1915. resolve_mailb(name)
  1916. char *name;             /* local username, without trailing dot */
  1917. {
  1918.     register struct rr *result_rrlp;
  1919.     struct rr *rrlp;
  1920.     char *sname;
  1921.  
  1922. #ifdef notdef
  1923.     /* Append trailing dot */
  1924.     sname = mallocw(strlen(name)+2);
  1925.     sprintf(sname,"%s.",name);
  1926. #else
  1927.     sname = strdup(name);
  1928. #endif
  1929.     rrlp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MB,0,0,NULL);
  1930.     rrlp->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MG,0,0,NULL);
  1931.     rrlp->next->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MR,0,0,NULL);
  1932.     free(sname);
  1933.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  1934.         result_rrlp = dfile_search(rrlp);
  1935.     }
  1936.     free_rr(rrlp);
  1937.     if(Dsuffix != NULLCHAR){
  1938.         rrlp = result_rrlp;
  1939.         while(rrlp != NULLRR){  /* add domain suffix to data */
  1940.             if(rrlp->rdlength > 0 &&
  1941.                rrlp->rdata.name[rrlp->rdlength-1] != '.'){
  1942.                 sname = mallocw((unsigned)rrlp->rdlength +
  1943.                     Dsuffixl+2);
  1944.                 sprintf(sname,"%s.%s",rrlp->rdata.name,Dsuffix);
  1945.                 free(rrlp->rdata.name);
  1946.                 rrlp->rdata.name = sname;
  1947.                 rrlp->rdlength = strlen(sname);
  1948.             }
  1949.             rrlp = rrlp->next;
  1950.         }
  1951.     }
  1952.     dcache_add(copy_rr_list(result_rrlp));
  1953.     return result_rrlp;
  1954. }
  1955.  
  1956. /* Return "normalized" domain name, with default suffix and trailing '.'
  1957.  * Searches local cache for CNAME expansions.
  1958.  */
  1959. char *
  1960. domainsuffix(dname)
  1961. char *dname;
  1962. {
  1963.     char *sname, *tname, *pp;
  1964.     int l;
  1965.  
  1966.     if ( dname == NULLCHAR )
  1967.         return NULLCHAR;
  1968.  
  1969.     if(isaddr(dname)) {
  1970.         /* convert to our canonic form */
  1971.         return strdup( inet_ntoa( aton(dname) ) );
  1972.     }
  1973.  
  1974.     sname = strdup(dname);
  1975.     l = strlen(sname);
  1976.     if((pp = strrchr(sname,'.')) == NULLCHAR){
  1977.         /* No dot in name. Try to add default suffix */
  1978.         if(Dsuffix != NULLCHAR){
  1979.             /* Append default suffix */
  1980.             tname = mallocw((unsigned)l+Dsuffixl+2);
  1981.             sprintf(tname,"%s.%s",sname,Dsuffix);
  1982.             free(sname);
  1983.             sname = tname;
  1984.         }
  1985.     } else {
  1986.         /* There is a dot in the name. Check last part of
  1987.          * name. If longer than 4 char it must be a name
  1988.          * 4 or less is probably a domain (org, army, uk)
  1989.          */
  1990.         if(Dsuffix != NULLCHAR){
  1991.             if(strlen(pp) <= 5){
  1992.                 for(++pp;*pp;pp++){
  1993.                     if(isdigit(*pp))
  1994.                         break;
  1995.                 }
  1996.                 if(*pp){
  1997.             /* Append default suffix */
  1998.                     tname = mallocw((unsigned)l+Dsuffixl+2);
  1999.                     sprintf(tname,"%s.%s",sname,Dsuffix);
  2000.                     free(sname);
  2001.                     sname = tname;
  2002.                 }
  2003.             } else {
  2004.             /* name with dot (must be call + local domain) */
  2005.                 tname = mallocw((unsigned)l+Dsuffixl+2);
  2006.                 sprintf(tname,"%s.%s",sname,Dsuffix);
  2007.                 free(sname);
  2008.                 sname = tname;
  2009.             }
  2010.         }
  2011.     }
  2012.  
  2013.     if(sname[strlen(sname)-1] != '.'){
  2014.         /* Append trailing dot */
  2015.         tname = mallocw(strlen(sname)+2);
  2016.         sprintf(tname,"%s.",sname);
  2017.         free(sname);
  2018.         sname = tname;
  2019.     }
  2020.  
  2021. #ifdef notdef
  2022.     struct rr *qrrp;
  2023.     struct rr *result_rrlp;
  2024.  
  2025.     qrrp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_CNAME,0,0,NULL);
  2026.     if ( (result_rrlp = dcache_search(qrrp)) != NULLRR
  2027.       || (result_rrlp = dfile_search(qrrp)) != NULLRR ) {
  2028.         free(sname);
  2029.         sname = strdup(result_rrlp->rdata.name);
  2030.     }
  2031.     free_rr(qrrp);
  2032.     free_rr(result_rrlp);
  2033. #endif
  2034.     return sname;
  2035. }
  2036.  
  2037. #ifdef DSERVER
  2038.  
  2039. /* Domain Name Server - based on the server in GRI-Nos 910828
  2040.  * ported to current NOS code by Johan. K. Reinalda, WG7J/PA3DIS
  2041.  *
  2042.  * - Does not answer more then one query per frame
  2043.  * - Gives non-authoritative answers to all queries.
  2044.  * - Does not reply with authority or additional RR's
  2045.  * - If no answers are found in local cache or domain.txt file,
  2046.  *   remote servers, if configured, are queried.
  2047.  *
  2048.  *
  2049.  * v0.93  10/19/92   queries do not recurse anymore, but let the requester
  2050.  *                   do the recursion (Solves problem with CNAME queries)
  2051.  * v0.92  06/24/92   RR length bug fixed.
  2052.  *                   A,CNAME,MX,HINFO,PTR,NS,SOA queries now work
  2053.  * v0.91  06/22/92   MX has small bug with RR length indication
  2054.  * v0.90  06/20/92   Only supports a single type 'A' request per frame
  2055.  */
  2056.  
  2057. int Dsocket = -1;
  2058.  
  2059. /* Process a query received by the DNS server */
  2060. static void
  2061. proc_query(unused,d,b)
  2062. int unused;
  2063. void *d;
  2064. void *b;
  2065. {
  2066.     struct dserver *dp;
  2067.     struct dhdr *dhdr;
  2068.     int i,len;
  2069.     char *buf;
  2070.     struct sockaddr_in server;
  2071.     struct rr *rrp, *rrans, *rrns, *rradd, *rrtmp;
  2072.     struct rr *qp;
  2073.  
  2074.     dp = (struct dserver *) d;      /* The query address */
  2075.     dhdr = (struct dhdr *) b;       /* The query in host format */
  2076.  
  2077.     rrans = rrns = rradd = NULLRR;
  2078.     qp = dhdr->questions;
  2079.  
  2080.     /* This loop does NOT support multiple questions yet */
  2081. #ifdef notdef
  2082.     for(i=0;i<dhdr->qdcount;i++){
  2083. #endif
  2084.  
  2085. #ifdef notdef
  2086.     /* For now, assume we don't have authority */
  2087.     if(haveaa(qp->name))
  2088.         dhdr->aa = 1;
  2089.     else
  2090. #endif
  2091.         dhdr->aa = 0;
  2092.     switch(qp->type) {
  2093.     case TYPE_A:
  2094.     case TYPE_MX:
  2095.     case TYPE_CNAME:
  2096.     case TYPE_HINFO:
  2097.     case TYPE_PTR:
  2098.     case TYPE_NS:
  2099.     case TYPE_SOA:
  2100.     /* Not all of the below types are implemented in resolve_rr() */
  2101. #ifdef notdef
  2102.     case TYPE_TXT:
  2103.     case TYPE_ANY:
  2104. #endif
  2105.         /* Let the other side resolve CNAME references, do not recurse ! */
  2106.         if((rrp = resolve_rr(qp->name,qp->type,0)) != NULLRR) {
  2107.         /* we found an entry, go tell him */
  2108.         dhdr->rcode = NO_ERROR;
  2109.         dhdr->qr = RESPONSE;
  2110.         } else {
  2111.         /* we did not find an entry, go tell him */
  2112.         rrp = (struct rr *)callocw(1,sizeof(struct rr));
  2113.         rrp->name = strdup(qp->name);
  2114.         rrp->type = qp->type;
  2115.         rrp->class = qp->class;
  2116.         rrp->ttl = 500L;
  2117.         rrp->rdata.addr = 0L;
  2118.         rrp->rdlength = 4;  /* size of addr data */
  2119.         dhdr->rcode = NAME_ERROR;
  2120.         dhdr->qr = RESPONSE;
  2121.         }
  2122.         rrans = rrp;
  2123.         break;
  2124.     /* Search only the local cache and domain file for these next few */
  2125.     /* Is this a good idea ??? */
  2126.     case TYPE_MB:
  2127.     case TYPE_MG:
  2128.     case TYPE_MR:
  2129.         rrp = make_rr(RR_QUERY,qp->name,CLASS_IN,qp->type,0,0,NULL);
  2130.         if((rrans = dcache_search(rrp)) == NULLRR){
  2131.         rrans = dfile_search(rrp);
  2132.         }
  2133.         free_rr(rrp);
  2134.         break;
  2135. #ifdef notdef
  2136.     /* Not implemented, yet (?) */
  2137.     case TYPE_MD:
  2138.     case TYPE_MF:
  2139.     case TYPE_WKS:
  2140.     case TYPE_NULL:
  2141.     case TYPE_MINFO:
  2142. #endif
  2143.     default:
  2144.         dhdr->rcode = NOT_IMPL;
  2145.         dhdr->qr = RESPONSE;
  2146.     }
  2147.     /* This loop does NOT support multiple questions yet */
  2148. #ifdef notdef
  2149.     qp = qp->next;  /* next question */
  2150.     }
  2151. #endif
  2152.  
  2153.     /* Find the number of answer records */
  2154.     i = 0;
  2155.     rrtmp = rrans;
  2156.     while(rrtmp != NULLRR) {
  2157.     i++;
  2158.     rrtmp = rrtmp->next;
  2159.     }
  2160.     dhdr->ancount = i;
  2161.     dhdr->answers = rrans;
  2162.  
  2163.     /* Authority and Additional RR's not implemented yet. */
  2164.     dhdr->nscount = 0;
  2165.     dhdr->authority = NULLRR;
  2166.     dhdr->arcount = 0;
  2167.     dhdr->additional = NULLRR;
  2168.  
  2169. #ifdef notdef
  2170.     /* Find the number of authority records */
  2171.     i = 0;
  2172.     rrtmp = rrns;
  2173.     while(rrtmp != NULLRR) {
  2174.     i++;
  2175.     rrtmp = rrtmp->next;
  2176.     }
  2177.     dhdr->nscount = i;
  2178.     dhdr->authority = rrns;
  2179.  
  2180.     /* Find the number of additional records */
  2181.     i = 0;
  2182.     rrtmp = rradd;
  2183.     while(rrtmp != NULLRR) {
  2184.     i++;
  2185.     rrtmp = rrtmp->next;
  2186.     }
  2187.     dhdr->arcount = i;
  2188.     dhdr->additional = rradd;
  2189. #endif
  2190.  
  2191.     if(Dtrace) {
  2192.     puts("DNS: replying");
  2193.     dumpdomain(dhdr,0);
  2194.     }
  2195.  
  2196.     /* Maximum reply size is 512, see rfc1034/1035 */
  2197.     buf = mallocw(512);
  2198.     len = htondomain(dhdr,buf,512);
  2199.     free_dhdr(dhdr);
  2200.  
  2201.     server.sin_family = AF_INET;
  2202.     server.sin_port = dp->port;
  2203.     server.sin_addr.s_addr = dp->address;
  2204.     sendto(Dsocket,buf,len,0,(char *)&server,sizeof(server));
  2205.     free(buf);
  2206.     free((char *)dp);
  2207. }
  2208.  
  2209.  
  2210. /* Process to receive all domain server related messages */
  2211. static void
  2212. drx(unused,u,p)
  2213. int unused;
  2214. void *u;
  2215. void *p;
  2216. {
  2217.     struct sockaddr_in sock,from;
  2218.     int fromlen;
  2219.     struct mbuf *bp;
  2220.     struct dhdr *dhdr;
  2221.     struct dserver *dp;
  2222.     int foo;
  2223.  
  2224.     Dsocket = socket(AF_INET,SOCK_DGRAM,0);
  2225.     sock.sin_family = AF_INET;
  2226.     sock.sin_addr.s_addr = INADDR_ANY;
  2227.     sock.sin_port = IPPORT_DOMAIN;
  2228.     if(bind(Dsocket,(char *)&sock,sizeof(sock)) == -1) {
  2229.     tputs("DNS: can't bind\n");
  2230.     Dsocket = -1;
  2231.     return;
  2232.     }
  2233.     /* Now loop forever, processing queries */
  2234.     for(;;){
  2235.         fromlen = sizeof(from);
  2236.     if((foo = recv_mbuf(Dsocket,&bp,0,(char *)&from,&fromlen)) == -1)
  2237.         break;  /* Server closing */
  2238.         if(foo == 0)
  2239.             continue;
  2240.         dhdr = mallocw(sizeof(struct dhdr));
  2241.         ntohdomain(dhdr,&bp);
  2242.     if(Dtrace) {
  2243.         printf("DNS: %u bytes from %s\n",foo,
  2244.         psocket((struct sockaddr *)&from));
  2245.         dumpdomain(dhdr,0);
  2246.     }
  2247.     /* Process queries only */
  2248.     if(dhdr->qr == QUERY) {
  2249.         /* Queries from ourself will cause a loop ! */
  2250.         if(ismyaddr((int32)from.sin_addr.s_addr) != NULLIF) {
  2251.         if(Dtrace)
  2252.             tputs("DNS: question from myself ignored\n");
  2253.         free_dhdr(dhdr);
  2254.         continue;
  2255.         } else {
  2256.         dp=(struct dserver *)callocw(1,sizeof(struct dserver));
  2257.         dp->address = from.sin_addr.s_addr;
  2258.         dp->srtt = (Dserver_maxwait * 1000L) / MSPTICK;
  2259.         dp->timeout = dp->srtt * 2;
  2260.         dp->port = from.sin_port;
  2261.         if(dhdr->opcode == ZONEINIT) {
  2262.             /* ZONEINIT not implemented */
  2263.             free_dhdr(dhdr);
  2264.             free(dp);
  2265. #ifdef notdef
  2266.             newproc("Domain zoneinit",1024,proc_bootp
  2267.                 ,0,(void *)dp,(void *)dhdr,0);
  2268. #endif
  2269.          } else
  2270.             newproc("Domain server",1024,proc_query
  2271.                 ,0,(void *)dp,(void *)dhdr,0);
  2272.             }
  2273.         }
  2274.     }
  2275. }
  2276.                 
  2277. static int
  2278. dodnsserver(argc,argv,p)
  2279. int argc;
  2280. char *argv[];
  2281. void *p;
  2282. {
  2283.     if(argc == 1) {
  2284.     tputs((Dsocket != -1) ? "on\n" : "off\n");
  2285.     } else {
  2286.     if(!stricmp(argv[1],"on")) {
  2287.         if(Dsocket == -1)
  2288.         /* Start domain server task */
  2289.         newproc("Domain listener",1024,drx,0,NULL,NULL,0);
  2290.     } else {
  2291.         close_s(Dsocket);
  2292.         Dsocket = -1;
  2293.     }
  2294.     }
  2295.     return 0;
  2296. }
  2297.  
  2298. /* Free a domain message */
  2299. static void
  2300. free_dhdr(dp)
  2301. struct dhdr *dp;
  2302. {
  2303.     if(dp->qdcount != 0)
  2304.     free_rr(dp->questions);
  2305.     if(dp->ancount != 0)
  2306.     free_rr(dp->answers);
  2307.     if(dp->nscount != 0)
  2308.     free_rr(dp->authority);
  2309.     if(dp->arcount != 0)
  2310.     free_rr(dp->additional);
  2311.     free((char *)dp);
  2312. }
  2313.  
  2314. #endif /* DSERVER */
  2315.  
  2316. #ifdef ALLCMD
  2317. int
  2318. dodomlook(argc,argv,p)
  2319. int argc;
  2320. char *argv[];
  2321. void *p;
  2322. {
  2323.     char **margv;
  2324.     margv = (char **)callocw(3,sizeof(char *));
  2325.     margv[1] = strdup(Dfile);
  2326.     margv[2] = strdup(argv[1]);
  2327.     domore(3,margv,p);
  2328.     free(margv[1]);
  2329.     free(margv[2]);
  2330.     free(margv);
  2331.     return 0;
  2332. }
  2333. #endif
  2334.  
  2335.